import streamlit as st
import pandas as pd
import plotly.express as px
import plotly.graph_objects as go
from datetime import datetime
import numpy as np
import os
import time
import logging
import sys
from io import StringIO

from api_client import StockApiClient
from stock_detail import stock_detail_app
from config import APP_TITLE, APP_DESCRIPTION, ALIYUN_APPCODE

# 页面配置
st.set_page_config(
    page_title=APP_TITLE,
    page_icon="📈",
    layout="wide",
    initial_sidebar_state="expanded"
)

# 初始化API客户端
@st.cache_resource
def get_api_client():
    return StockApiClient(app_code=ALIYUN_APPCODE)

# 设置日志捕获器
class StreamlitLogHandler(logging.Handler):
    def __init__(self, placeholder):
        super().__init__()
        self.placeholder = placeholder
        self.logs = []
        self.formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
    
    def emit(self, record):
        log_entry = self.formatter.format(record)
        self.logs.append(log_entry)
        # 只显示最新的50条日志
        log_text = "\n".join(self.logs[-50:])
        self.placeholder.text_area("API 调用日志", log_text, height=300)

def main():
    # 页面标题
    st.title(APP_TITLE)
    st.caption(APP_DESCRIPTION)
    
    # 侧边栏 - 功能选择
    st.sidebar.header("功能选择")
    app_mode = st.sidebar.selectbox(
        "选择功能模式",
        ["价值投资分析", "大跌股票分析", "市场概览", "个股分析"]
    )
    
    # 根据选择的功能显示不同的内容
    if app_mode == "价值投资分析":
        value_investment_app()
    elif app_mode == "大跌股票分析":
        price_drop_app()
    elif app_mode == "个股分析":
        stock_detail_app()
    else:
        market_overview_app()

def value_investment_app():
    """格雷厄姆价值投资分析功能"""
    st.header("格雷厄姆价值投资分析")
    st.markdown("基于格雷厄姆价值投资理念，筛选A股市场中被低估且有低吸机会的股票")
    
    # 参数设置
    with st.expander("参数设置", expanded=True):
        col1, col2 = st.columns(2)
        
        with col1:
            # 成交额排名
            limit = st.slider(
                "获取股票数量", 
                min_value=50, 
                max_value=500, 
                value=100,
                step=50,
                key="vi_limit"
            )
            
            # 价值股筛选参数
            st.subheader("价值股筛选标准")
            
            pe_threshold = st.slider(
                "市盈率(PE)上限", 
                min_value=5, 
                max_value=30, 
                value=15,
                step=1,
                key="vi_pe"
            )
            
            pb_threshold = st.slider(
                "市净率(PB)上限", 
                min_value=0.5, 
                max_value=3.0, 
                value=1.5,
                step=0.1,
                key="vi_pb"
            )
        
        with col2:
            div_yield_threshold = st.slider(
                "股息率(%)下限", 
                min_value=1.0, 
                max_value=10.0, 
                value=4.0,
                step=0.5,
                key="vi_div"
            )
            
            market_cap_threshold = st.slider(
                "市值下限(亿元)", 
                min_value=10, 
                max_value=500, 
                value=100,
                step=10,
                key="vi_cap"
            )
            
            # 低吸参数
            st.subheader("低吸策略参数")
            
            drop_min = st.slider(
                "最小跌幅(%)", 
                min_value=1.0, 
                max_value=5.0, 
                value=2.0,
                step=0.5,
                key="vi_drop_min"
            )
            
            drop_max = st.slider(
                "最大跌幅(%)", 
                min_value=3.0, 
                max_value=10.0, 
                value=6.0,
                step=0.5,
                key="vi_drop_max"
            )
    
    # 获取数据按钮
    if st.button("分析价值股", key="btn_value_stocks"):
        with st.spinner("正在获取和分析股票数据..."):
            try:
                # 创建进度条
                progress_bar = st.progress(0)
                status_text = st.empty()
                
                # 更新状态
                status_text.text("正在初始化API客户端...")
                progress_bar.progress(10)
                
                api_client = get_api_client()
                
                # 更新状态
                status_text.text("正在获取股票数据...")
                progress_bar.progress(30)
                
                # 创建日志容器
                log_tabs = st.tabs(["分析结果", "处理日志"])
                
                with log_tabs[1]:
                    col1, col2 = st.columns([1, 1])
                    
                    with col1:
                        console_log = st.empty()
                    
                    with col2:
                        api_log = st.empty()
                
                # 设置日志处理器
                log_handler = StreamlitLogHandler(api_log)
                root_logger = logging.getLogger()
                root_logger.addHandler(log_handler)
                
                # 使用StringIO捕获控制台输出
                old_stdout = sys.stdout
                sys.stdout = mystdout = StringIO()
                
                # 获取价值股
                data, error = api_client.get_value_stocks(
                    pe_threshold=pe_threshold,
                    pb_threshold=pb_threshold,
                    div_yield_threshold=div_yield_threshold,
                    market_cap_threshold=market_cap_threshold,
                    drop_min=drop_min,
                    drop_max=drop_max,
                    limit=limit
                )
                
                # 恢复标准输出
                sys.stdout = old_stdout
                
                # 显示控制台输出
                console_log.text_area("控制台输出", mystdout.getvalue(), height=300)
                
                # 移除日志处理器
                root_logger.removeHandler(log_handler)
                
                # 更新状态
                status_text.text("分析完成!")
                progress_bar.progress(100)
                
                with log_tabs[0]:
                    if error:
                        st.error(f"获取数据失败: {error}")
                    elif data.empty:
                        st.warning("没有找到符合条件的价值股")
                    else:
                        # 显示结果
                        st.subheader(f"符合格雷厄姆标准且跌幅在{drop_min}%-{drop_max}%的价值股")
                        
                        # 显示数据表格
                        st.dataframe(data[['代码', '名称', '最新价', '涨跌幅', '市盈率', '市净率', '总市值(亿)']], use_container_width=True)
                        
                        # 创建可视化图表
                        create_value_stock_visualizations(data)
                        
                        # 显示投资建议
                        show_investment_advice(data, drop_max)
            except Exception as e:
                st.error(f"分析过程中出错: {str(e)}")
    else:
        # 首次加载页面时显示的内容
        st.info("👆 请设置参数并点击'分析价值股'按钮开始分析")
        st.markdown("""
        ### 格雷厄姆价值投资理念
        
        本功能基于本杰明·格雷厄姆的价值投资理念，结合A股市场特点，筛选被低估且有低吸机会的股票。
        
        #### 核心筛选标准
        
        - **市盈率(PE)低：** 低于行业平均或历史均值（格雷厄姆喜欢PE<15）
        - **市净率(PB)低：** PB<1.5，最好<1，代表股价低于每股净资产
        - **股息率高：** >3%-4%，证明公司赚钱还分红
        - **市值要求：** 大公司（市值>100亿，A股蓝筹多），财务稳健
        
        #### 低吸策略
        
        从成交额较大的股票中，筛选出符合格雷厄姆价值投资标准，且当日跌幅在2%-6%的股票，提供低吸机会。
        """)

def price_drop_app():
    """大跌股票分析功能"""
    st.header("大跌股票分析")
    st.markdown("分析昨日成交量前N名的股票中，今日跌幅最大的M只股票")
    
    # 参数设置
    with st.expander("参数设置", expanded=True):
        col1, col2 = st.columns(2)
        
        with col1:
            # 成交量排名
            top_volume = st.slider(
                "成交量前N名", 
                min_value=50, 
                max_value=500, 
                value=100,
                step=50,
                key="pd_volume"
            )
        
        with col2:
            # 跌幅排名
            top_drop = st.slider(
                "跌幅前M名", 
                min_value=5, 
                max_value=50, 
                value=10,
                step=5,
                key="pd_drop"
            )
    
    # 获取数据按钮
    if st.button("分析大跌股票", key="btn_price_drop"):
        with st.spinner("正在获取和分析股票数据..."):
            try:
                # 创建进度条
                progress_bar = st.progress(0)
                status_text = st.empty()
                
                # 更新状态
                status_text.text("正在初始化API客户端...")
                progress_bar.progress(10)
                
                api_client = get_api_client()
                
                # 更新状态
                status_text.text("正在获取股票数据...")
                progress_bar.progress(30)
                
                # 创建日志容器
                log_tabs = st.tabs(["分析结果", "处理日志"])
                
                with log_tabs[1]:
                    col1, col2 = st.columns([1, 1])
                    
                    with col1:
                        console_log = st.empty()
                    
                    with col2:
                        api_log = st.empty()
                
                # 设置日志处理器
                log_handler = StreamlitLogHandler(api_log)
                root_logger = logging.getLogger()
                root_logger.addHandler(log_handler)
                
                # 使用StringIO捕获控制台输出
                old_stdout = sys.stdout
                sys.stdout = mystdout = StringIO()
                
                # 获取股票排行
                stocks = api_client.get_stock_rank(sort_field="value", ascending=False, limit=top_volume)
                
                if stocks.empty:
                    error = "无法获取股票排行数据"
                    data = pd.DataFrame()
                else:
                    # 计算跌幅
                    stocks['change_rate'] = pd.to_numeric(stocks['changeRate'], errors='coerce')
                    
                    # 按跌幅排序（升序，跌幅越大排名越前）
                    data = stocks.sort_values(by='change_rate', ascending=True).head(top_drop)
                    
                    # 重命名列
                    data = data.rename(columns={
                        'symbol': '代码',
                        'name': '名称',
                        'price': '最新价',
                        'change_rate': '涨跌幅',
                        'volume': '成交量',
                        'value': '成交额',
                        'high': '最高价',
                        'low': '最低价',
                        'open': '开盘价',
                        'preclose': '昨收价'
                    })
                    
                    error = None
                
                # 恢复标准输出
                sys.stdout = old_stdout
                
                # 显示控制台输出
                console_log.text_area("控制台输出", mystdout.getvalue(), height=300)
                
                # 移除日志处理器
                root_logger.removeHandler(log_handler)
                
                # 更新状态
                status_text.text("分析完成!")
                progress_bar.progress(100)
                
                with log_tabs[0]:
                    if error:
                        st.error(f"获取数据失败: {error}")
                    elif data.empty:
                        st.warning("没有找到符合条件的大跌股票")
                    else:
                        # 显示结果
                        st.subheader(f"昨日成交量前{top_volume}名中跌幅最大的{top_drop}只股票")
                        
                        # 显示数据表格
                        st.dataframe(data[['代码', '名称', '最新价', '涨跌幅', '成交量', '成交额']], use_container_width=True)
                        
                        # 创建可视化图表
                        create_price_drop_visualizations(data)
            except Exception as e:
                st.error(f"分析过程中出错: {str(e)}")
    else:
        # 首次加载页面时显示的内容
        st.info("👆 请设置参数并点击'分析大跌股票'按钮开始分析")
        st.markdown("""
        ### 大跌股票分析策略
        
        本功能分析昨日成交量前N名的股票中，今日跌幅最大的M只股票，帮助您发现可能的低吸机会。
        
        #### 分析逻辑
        
        1. 获取昨日成交量前N名的股票列表
        2. 获取这些股票的今日价格数据
        3. 计算跌幅并排序，找出跌幅最大的M只股票
        
        #### 投资策略建议
        
        - 关注大跌股票的基本面，避免"接飞刀"
        - 结合技术指标和成交量变化判断是否为超跌
        - 分批建仓，避免一次性投入过多资金
        """)

def market_overview_app():
    """市场概览功能"""
    st.header("A股市场概览")
    st.markdown("提供A股市场的整体情况和热点板块分析")
    
    # 获取数据按钮
    if st.button("获取市场数据", key="btn_market"):
        with st.spinner("正在获取市场数据..."):
            try:
                # 创建进度条
                progress_bar = st.progress(0)
                status_text = st.empty()
                
                # 更新状态
                status_text.text("正在初始化API客户端...")
                progress_bar.progress(10)
                
                api_client = get_api_client()
                
                # 更新状态
                status_text.text("正在获取指数数据...")
                progress_bar.progress(30)
                
                # 获取指数数据
                indices = api_client.get_stock_quotes(["sh000001", "sz399001", "sz399006"])
                
                # 更新状态
                status_text.text("正在获取涨幅榜...")
                progress_bar.progress(60)
                
                # 获取涨幅榜
                top_gainers = api_client.get_stock_rank(sort_field="changeRate", ascending=False, limit=10)
                
                # 更新状态
                status_text.text("正在获取跌幅榜...")
                progress_bar.progress(80)
                
                # 获取跌幅榜
                top_losers = api_client.get_stock_rank(sort_field="changeRate", ascending=True, limit=10)
                
                # 更新状态
                status_text.text("分析完成!")
                progress_bar.progress(100)
                
                # 显示市场概览
                st.subheader("大盘指数")
                
                if not indices.empty:
                    # 创建指数表格
                    indices_data = []
                    for _, index in indices.iterrows():
                        indices_data.append({
                            "指数名称": index["name"],
                            "最新点位": float(index["price"]),
                            "涨跌幅": f"{float(index['changeRate']):.2f}%",
                            "涨跌额": float(index["change"]),
                            "成交量(万手)": float(index["volume"]) / 10000,
                            "成交额(亿元)": float(index["value"]) / 100000000
                        })
                    
                    indices_df = pd.DataFrame(indices_data)
                    st.dataframe(indices_df, use_container_width=True)
                    
                    # 创建指数涨跌幅可视化
                    fig = px.bar(
                        indices_df,
                        x="指数名称",
                        y=[float(x.strip('%')) for x in indices_df["涨跌幅"]],
                        color=[float(x.strip('%')) for x in indices_df["涨跌幅"]],
                        color_continuous_scale=["red", "lightgrey", "green"],
                        range_color=[-2, 2],
                        labels={"y": "涨跌幅(%)", "x": "指数名称"},
                        title="大盘指数涨跌幅"
                    )
                    st.plotly_chart(fig, use_container_width=True)
                
                # 显示涨跌幅榜
                col1, col2 = st.columns(2)
                
                with col1:
                    st.subheader("涨幅榜 Top 10")
                    if not top_gainers.empty:
                        gainers_df = pd.DataFrame({
                            "代码": top_gainers["symbol"],
                            "名称": top_gainers["name"],
                            "最新价": pd.to_numeric(top_gainers["price"]),
                            "涨跌幅(%)": pd.to_numeric(top_gainers["changeRate"]).round(2)
                        })
                        st.dataframe(gainers_df, use_container_width=True)
                        
                        # 创建涨幅榜可视化
                        fig = px.bar(
                            gainers_df.head(10),
                            y="名称",
                            x="涨跌幅(%)",
                            orientation='h',
                            color="涨跌幅(%)",
                            color_continuous_scale="Greens",
                            labels={"涨跌幅(%)": "涨幅(%)", "名称": "股票名称"},
                            title="涨幅榜 Top 10"
                        )
                        st.plotly_chart(fig, use_container_width=True)
                
                with col2:
                    st.subheader("跌幅榜 Top 10")
                    if not top_losers.empty:
                        losers_df = pd.DataFrame({
                            "代码": top_losers["symbol"],
                            "名称": top_losers["name"],
                            "最新价": pd.to_numeric(top_losers["price"]),
                            "涨跌幅(%)": pd.to_numeric(top_losers["changeRate"]).round(2)
                        })
                        st.dataframe(losers_df, use_container_width=True)
                        
                        # 创建跌幅榜可视化
                        fig = px.bar(
                            losers_df.head(10),
                            y="名称",
                            x="涨跌幅(%)",
                            orientation='h',
                            color="涨跌幅(%)",
                            color_continuous_scale="Reds_r",
                            labels={"涨跌幅(%)": "跌幅(%)", "名称": "股票名称"},
                            title="跌幅榜 Top 10"
                        )
                        st.plotly_chart(fig, use_container_width=True)
            except Exception as e:
                st.error(f"获取市场数据时出错: {str(e)}")
    else:
        # 首次加载页面时显示的内容
        st.info("👆 请点击'获取市场数据'按钮查看最新市场概览")
        st.markdown("""
        ### 市场概览功能
        
        本功能提供A股市场的整体情况和热点板块分析，帮助您了解市场动态。
        
        #### 主要内容
        
        - **大盘指数**：上证指数、深证成指、创业板指的最新行情
        - **涨幅榜**：当日涨幅最大的10只股票
        - **跌幅榜**：当日跌幅最大的10只股票
        
        #### 使用建议
        
        - 定期查看市场概览，了解市场整体趋势
        - 关注热点板块和个股，把握投资机会
        - 结合其他功能进行深入分析
        """)

def create_value_stock_visualizations(data):
    """创建价值股数据可视化图表"""
    # 创建两列布局
    col1, col2 = st.columns(2)
    
    with col1:
        # 跌幅排名条形图
        try:
            # 确保数据不为空
            if len(data) > 0:
                fig_drop = px.bar(
                    data.sort_values('涨跌幅', ascending=True).head(10),
                    y='名称',
                    x='涨跌幅',
                    orientation='h',
                    title="跌幅排名",
                    labels={'涨跌幅': '跌幅(%)', '名称': '股票名称'},
                    color='涨跌幅',
                    color_continuous_scale='Reds'
                )
                fig_drop.update_layout(height=500)
                st.plotly_chart(fig_drop, use_container_width=True)
            else:
                st.info("没有足够的数据来创建跌幅排名图表")
        except Exception as e:
            st.warning(f"创建跌幅排名图表时出错: {str(e)}")
    
    with col2:
        # 市值分布饼图
        try:
            # 确保总市值列存在且有值
            if '总市值(亿)' in data.columns and not data['总市值(亿)'].isna().all():
                # 创建市值区间
                data['市值区间'] = pd.cut(
                    data['总市值(亿)'],
                    bins=[0, 100, 300, 500, 1000, float('inf')],
                    labels=['<100亿', '100-300亿', '300-500亿', '500-1000亿', '>1000亿']
                )
                
                market_cap_counts = data['市值区间'].value_counts().reset_index()
                market_cap_counts.columns = ['市值区间', 'count']
                
                fig_market_cap = px.pie(
                    market_cap_counts,
                    values='count',
                    names='市值区间',
                    title="市值分布",
                    color_discrete_sequence=px.colors.qualitative.Set3
                )
                fig_market_cap.update_layout(height=500)
                st.plotly_chart(fig_market_cap, use_container_width=True)
            else:
                st.info("没有足够的数据来创建市值分布图表")
        except Exception as e:
            st.warning(f"创建市值分布图表时出错: {str(e)}")

def create_price_drop_visualizations(data):
    """创建大跌股票数据可视化图表"""
    # 创建跌幅排名条形图
    try:
        # 确保数据不为空
        if len(data) > 0:
            fig_drop = px.bar(
                data.sort_values('涨跌幅', ascending=True),
                y='名称',
                x='涨跌幅',
                orientation='h',
                title="跌幅排名",
                labels={'涨跌幅': '跌幅(%)', '名称': '股票名称'},
                color='涨跌幅',
                color_continuous_scale='Reds'
            )
            st.plotly_chart(fig_drop, use_container_width=True)
            
            # 创建成交量与跌幅散点图
            fig_scatter = px.scatter(
                data,
                x='涨跌幅',
                y='成交量',
                size='成交额',
                color='涨跌幅',
                hover_name='名称',
                color_continuous_scale='Reds',
                title="成交量与跌幅关系",
                labels={'涨跌幅': '跌幅(%)', '成交量': '成交量', '成交额': '成交额'}
            )
            st.plotly_chart(fig_scatter, use_container_width=True)
        else:
            st.info("没有足够的数据来创建可视化图表")
    except Exception as e:
        st.warning(f"创建可视化图表时出错: {str(e)}")

def show_investment_advice(data, drop_max):
    """显示投资建议"""
    st.subheader("投资建议")
    
    # 计算建议的投资组合
    if len(data) >= 5:
        # 按跌幅排序，选择跌幅最大的5只股票
        portfolio = data.sort_values('涨跌幅', ascending=True).head(5)
        
        st.markdown(f"""
        ### 建议投资组合
        
        基于格雷厄姆的价值投资理念和低吸策略，我们建议您考虑以下投资组合：
        
        1. **分散投资：** 从上述结果中选择跌幅接近{drop_max}%的5只股票
        2. **资金分配：** 假设总投资金额为50万元，每只股票分配10万元
        3. **买入策略：** 在当日收盘前买入，或等待次日继续回调时买入
        4. **持有策略：** 中长期持有，等待价值回归
        5. **止盈策略：** 当股价上涨10%-20%时考虑部分止盈
        """)
        
        # 显示建议投资组合
        st.markdown("#### 建议投资的5只股票")
        
        # 创建投资组合表格
        portfolio_table = portfolio[['代码', '名称', '最新价', '涨跌幅']].copy()
        portfolio_table['建议投资金额'] = "10万元"
        portfolio_table['预计可买入股数'] = (100000 / portfolio_table['最新价']).astype(int)
        
        st.dataframe(portfolio_table, use_container_width=True)
        
        # 显示投资注意事项
        st.markdown("""
        ### 投资注意事项
        
        1. **风险提示：** 股市有风险，投资需谨慎，本建议不构成投资建议
        2. **基本面分析：** 在投资前，请进一步研究公司的基本面、行业前景和财务状况
        3. **市场风险：** 即使是价值股，短期内也可能因市场情绪或宏观因素而下跌
        4. **长期视角：** 价值投资强调长期持有，不要因短期波动而恐慌卖出
        5. **定期复盘：** 每季度或半年检查一次投资组合，根据公司基本面变化调整
        """)
    else:
        st.info("没有足够的数据来提供投资建议，请调整筛选条件后重试")

if __name__ == "__main__":
    main()
